﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml.Linq;
using Ionic.Zlib;

namespace TicTacToe.Core.Persistance
{
    public sealed class SavedGame
    {
        public Player Player1 { get; private set; }
        public Player Player2 { get; private set; }
        public IEnumerable<Turn> Turns { get; private set; }
        public DateTime SaveTime { get; private set; }
        public string Filename { get; private set; }

        XElement Serialize(string rootName)
        {
            return new XElement(rootName,
                new XElement("savetime", SaveTime),
                new XElement("player1", Player1.Serialize()),
                new XElement("player2", Player2.Serialize()),
                new XElement("turns",
                    from t in Turns.OrderBy(n => n.Timestamp)
                    select t.Serialize()));
        }

        // 'constructor'
        internal static SavedGame SaveGame(TicTacToeGame game)
        {
            var sg = new SavedGame
            {
                SaveTime = DateTime.Now,
                Player1 = game.PlayerOne,
                Player2 = game.PlayerTwo,
                Turns = game.Turns.OrderBy(n => n.Timestamp),
            };

            sg.Save();
            return sg;
        }

        internal static SavedGame LoadGame(string fromFile)
        {
            XElement e;

            var fs = File.OpenRead(fromFile);
            using (var zipStream = new GZipStream(fs, CompressionMode.Decompress))
                e = XElement.Load(zipStream);
            fs.Dispose();

            return new SavedGame
            {
                SaveTime = DateTime.Parse(e.Element("savetime").Value),
                Player1 = e.Element("player1").Element("player").DeserializeToPlayer(),
                Player2 = e.Element("player2").Element("player").DeserializeToPlayer(),
                Turns = (from t in e.Element("turns").Elements()
                         select t.DeserializeToTurn()).OrderBy(n => n.Timestamp),
                Filename = fromFile,
            };
        }

        // //

        internal void Save()
        {
            if (string.IsNullOrEmpty(Filename))
                Filename = Path.Combine(GameManager.SaveFilePath, SaveTime.Ticks + ".xml.gz");

            if (!Directory.Exists(GameManager.SaveFilePath))
                Directory.CreateDirectory(GameManager.SaveFilePath);

            var fs = File.Exists(Filename) ? new FileStream(Filename, FileMode.Truncate, FileAccess.Write) :
                new FileStream(Filename, FileMode.CreateNew, FileAccess.Write);

            using (var zipStream = new GZipStream(fs, CompressionMode.Compress, CompressionLevel.BestCompression))
                Serialize("savedgame").Save(zipStream);
            fs.Dispose();
        }

        private SavedGame() { } // prevent creating instances of this class
    }
}
